
import { TableInterface } from "./sqlite.service";
import { ObjectDto } from "./object.dto";
import { VerifyService } from "./verify.service";
import { ConditionFetch } from "./condition-fetch";

// @Injectable()
export class SqliteUtil {
  constructor(

  ) {
    //
  }

  objToString(obj: object = {}): string {
    let str: string = "";
    for (let key of Object.keys(obj)) {
      str += key + ' ' + obj[key] + ",";
    }
    str = str.length > 0 ? str.substr(0, str.length - 1) : str;
    return str;
  }


  splitObj(constructor: TableInterface, obj: object = {}): { keys: Array<string>, values: Array<string | number> } {
    let attr: string = "";
    let val: string = "";

    obj = new VerifyService().verifyType(constructor, obj);
    let keys = [];
    let values = [];
    for (let key of Object.keys(obj)) {
      obj[key] = this.booleanToNumber(obj[key]);
      let value;
      // console.log(obj[key]);
      // if (typeof(obj[key]) !== 'boolean') {
      //   value = obj[key] || obj[key] === 0 ? obj[key] : null;
      // }
      // console.log(obj[key]);
      value = obj[key] || obj[key] === 0 || obj[key] === false ? obj[key] : null;
      if (value === null) {
        continue;
      }
      val += ',' + value;
      attr += ',' + key;

      keys.push(key);
      values.push(value);
    }
    // attr = attr.length > 0 ? attr.substr(1, attr.length - 1) : attr;
    // val = val.length > 0 ? val.substr(1, val.length - 1) : val;
    // console.log({
    //   key: attr,
    //   value: val
    // }, '+++++++++');
    return {
      keys,
      values
    };
  }

  booleanToNumber(val: any): any {

    if (typeof(val) === "boolean") {
      return val ? 1 : 0;
    }
    return val;
   }

  splitAndSplice(obj: { keys: Array<string>, values: Array<string | number> }): Array<string> {
    let newObj = [];
    if (!obj || obj.keys.length <= 0) {
      return null;
    }
    // let key = obj.keys.split(',');
    // let value = obj.values.split(',');
    if (obj.keys.length !== obj.values.length) {
      return null;
    }

    obj.keys.forEach((item, index) => {
      newObj.push(`${item} = ${obj.values[index]}`);
    });

    return newObj;
  }

  conditionSplice(arr: Array<string>, split): string {
    let str = "";
    arr.forEach((item, index) => {
      if (index === arr.length - 1) {
        str += item;
      } else {
        str += `${item} ${split} `;
      }
    });
    return str;
  }

  whereKeyValues<T extends ObjectDto>(dto: T, obj: ConditionFetch) {
    let condition = {
      and: [],
      like: [],
      or: [],
      limit: ""
    };

    if (obj["and"]) {
      obj["and"] = new VerifyService().verifyType(dto.table(), obj["and"]);
      for (let key of Object.keys(obj["and"])) {
        condition["and"].push(`${key} = ${obj["and"][key]}`);
      }
    }

    if (obj["like"]) {
      // obj["like"] = new VerifyService().verifyType(model.table(), obj["like"]);
      for (let key of Object.keys(obj["like"])) {
        condition["like"].push(`${key} like "%${obj["like"][key]}%"`);
      }
    }

    if (obj["or"] && obj["or"].length > 0) {
      obj["or"].forEach((item, index) => {
        let newItem = new VerifyService().verifyType(dto.table(), item);
        let tem = {};
        for (let key of Object.keys(newItem)) {
          tem[key] = `${key} = ${newItem[key]}`;
          // condition["or"].push(`${key} = ${item[key]}`);
        }
        condition["or"].push(tem);
      });
    }

    if (obj["page"]) {
      if (obj["page"]["pageNo"]) {
        if (obj["page"]["pageSize"]) {
          condition["limit"] += ` limit ${obj["page"]["pageSize"]} offset ${(obj["page"]["pageNo"] - 1) * obj["page"]["pageSize"]}`;
        } else {
          condition["limit"] += ` limit 10 offset ${(obj["page"]["pageNo"] - 1) * 10} `;
        }
      }
    }
    return condition;
  }

  where<T extends ObjectDto>(modelClass: { new(): T; }, obj: ConditionFetch) {
    let condition = {
      and: [],
      like: [],
      or: [],
      in: "",
      limit: ""
    };
    let model = new modelClass();

    if (obj["and"]) {
      obj["and"] = new VerifyService().verifyType(model.table(), obj["and"]);
      for (let key of Object.keys(obj["and"])) {
        if (typeof(obj["and"][key]) === "object") {
          condition["and"].push(`${key} ${obj["and"][key]["symbol"]} ${obj["and"][key]["value"]}`);
        } else {
          condition["and"].push(`${key} = ${obj["and"][key]}`);
        }
      }
    }

    if (obj["like"]) {
      // obj["like"] = new VerifyService().verifyType(model.table(), obj["like"]);
      for (let key of Object.keys(obj["like"])) {
        condition["like"].push(`${key} like "%${obj["like"][key]}%"`);
      }
    }
    /*
    only implement [{key1: [1, 2, 3]}], length more then one have not implement
    ro : [{key1: [1, 2, 3]}]  | [{key1: value, key2: value}, {key1: value, key2: value}]
     */
    if (obj["or"] && obj["or"].length > 0) {
      // make Array value to [{key1: value, key2: value}, {key1: value, key2: value}]
      // this.StringArrayToObjectArray();
      if (obj["or"].length === 1 ) {

        if (this.StringArrayToObjectArray(obj["or"])) {
          obj["or"] = this.StringArrayToObjectArray(obj["or"]);
        }
      }
      obj["or"].forEach((item, index) => {
        let newItem = new VerifyService().verifyType(model.table(), item);
        let tem = {};
        for (let key of Object.keys(newItem)) {
          tem[key] = `${key} = ${newItem[key]}`;
          // condition["or"].push(`${key} = ${item[key]}`);
        }
        condition["or"].push(tem);
      });
    }

    if (obj["in"]) {
      condition["in"] = this.getInStr(this.inConditionSplit(model.table(), obj["in"]));
    }

    if (obj["page"]) {
      if (obj["page"]["pageNo"]) {
        if (obj["page"]["pageSize"]) {
          condition["limit"] += ` limit ${obj["page"]["pageSize"]} offset ${(obj["page"]["pageNo"] - 1) * obj["page"]["pageSize"]}`;
        } else {
          condition["limit"] += ` limit 10 offset ${(obj["page"]["pageNo"] - 1) * 10} `;
        }
      }
    }


    return condition;
  }

  whereSplice(and, or, like = [], limit = "", order: Array<string> = [], inCondition: string = ""): string {
    let condition = "";
    if (and.length >= 1) {
      condition = `where ( ${this.conditionSplice(and, "and")} )`;
      // where id = 1 and log = "test"
      if (like && like.length > 0) {
        condition += ` and ( ${this.conditionSplice(like, "and")} )`;

        if (or.length >= 1) {
          /*
          [{
           month: "month = "6"",
           year: "year = "2018""
           },{
           month: "month = "5"",
           year: "year = "2018""
           }]
           */
          // and (month = "6" and year = "2018") or (month = "5" and year = "2018")
          let orConditionStatement = this.orSplice(or);
          condition += ` and ${orConditionStatement}`;
          // and (price = 32 or attr = "re")
        }
      } else {
        if (or.length >= 1) {
          condition += ` and ${this.orSplice(or)}`;
          // and (price = 32 or attr = "re")
        }
      }
      // where id = 1 and log = "test" or (price = 32 or attr = "re")
    } else {
      if (like && like.length > 0) {
        condition += ` where ( ${this.conditionSplice(like, "and")} )`;

        if (or.length >= 1) {
          // condition = this.orSplice(or);
          condition += ` or ${this.orSplice(or)}`;
          // or (price = 32 or attr = "re")
        }
      } else {
        if (or.length >= 1) {
          // condition = this.orSplice(or);
          condition = `where ${this.orSplice(or)}`;
          // where (price = 32 or attr = "re")
        }
      }
    }
    if (inCondition.length > 0) {
      if (condition.length > 0) {
        condition += `and ${inCondition}`;
      } else {
        condition += `where ${inCondition}`;
      }
    }
    if (order.length >= 1) {
      condition += ` order by ${this.conditionSplice(order, " ")}`;
    }
    if (limit) {
      condition += limit;
    }
    return condition;
  }


  inConditionSplit(constructor: TableInterface, obj) {
    // let tem = {};
    for (let key of Object.keys(obj)) {
      let flag = "";
      for (let k of Object.keys(constructor.tableConstructor)) {
        if (key === k) {
          let regText = new RegExp("text");
          let regboolean = new RegExp("boolean");
          let data = "";
          if (regText.test(constructor.tableConstructor[k]) || regboolean.test(constructor.tableConstructor[k])) {
            data = obj[key].reduce((data2, list) => {
              return data2 += `"${list}",`;
            }, "");
          } else {
            data = obj[key].reduce((data2, list) => {
              console.log(data2);
              return data2 += `${list},`;
            }, "");
          }
          obj[key] = data.substring(0, data.length - 1);
        }
      }
    }
    return obj;
    /*
    {
    attr: '"1", "2", "3"',
    attr2: "1,2,3,4"}
     */

  }

  getInStr(obj) {
    let str = "";
    for (let key in obj) {
      str += ` ${key} in (${obj[key]}) and`;
    }
    if (str.length > 0) {
      str = str.substring(0, str.length - 3);
    }
    return str;
  }

  orSplice(or: Array<object>) {
    let orItems = [];
    // let str = '';
    or.forEach((item, index) => {
      // tslint:disable-next-line:forin
      for (let key in item) {
        orItems.push(item[key]);
      }
      // if(index === 0) {
      //   // ["month="6"", "year = "2018""]
      //   str += `(${this.conditionSplice(tem, "and")}) `
      // } else {
      //   str += `or (${this.conditionSplice(tem, "and")}) `
      // }
      // tem = [];
    });
    // if(or.length > 1) {
    //   str = `(${str})`;
    // }
    return `(${orItems.join(" or ")})`;
  }

  filterEmptyAttr(modelClass, keys: Array<string> = []) {
    let attrArray = Object.getOwnPropertyNames(modelClass);
    if (keys && keys.length > 0) {
      attrArray = attrArray.filter((key) => keys.indexOf(key) >= 0);
    }
    return attrArray.reduce((json, key) => {
      let value = modelClass[key];
      if (value || value === 0 || value === false) {
        json[key] = value;
      }
      return json;
    }, {} as { [key: string]: any });
  }

  // [{key1: [1, 2, 3]}, {key2: [3, 4, 5]}] => [{key1: 1},{key1: 2}, {key1: 3}]



  StringArrayToObjectArray(stringArray: Array<object>) {
    let arrayKey = "";
    for (let key in stringArray[0]) {
      arrayKey = key;
      break;
    }
    if (Array.isArray(stringArray[0][arrayKey])) {
      return stringArray[0][arrayKey].map((value) => {
        let tem: object = {};
        tem[arrayKey] = value;
        return tem;
        // return {
        //   `${key}`: value
        // };
      });
    } else {
      return null;
    }
  }
}
